package io.geekidea.springbootplus.system.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.geekidea.springbootplus.config.WxMaConfiguration;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.core.validator.groups.Add;
import io.geekidea.springbootplus.framework.core.validator.groups.Update;
import io.geekidea.springbootplus.framework.log.annotation.Module;
import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
import io.geekidea.springbootplus.system.annotations.CurrentAdmin;
import io.geekidea.springbootplus.system.annotations.CurrentAdminInfo;
import io.geekidea.springbootplus.system.annotations.CurrentCarrier;
import io.geekidea.springbootplus.system.annotations.CurrentCarrierInfo;
import io.geekidea.springbootplus.system.constant.TaskStatusConstant;
import io.geekidea.springbootplus.system.entity.Dormitory;
import io.geekidea.springbootplus.system.entity.ParcelCenter;
import io.geekidea.springbootplus.system.entity.Schedule;
import io.geekidea.springbootplus.system.entity.Task;
import io.geekidea.springbootplus.system.param.SchedulePageParam;
import io.geekidea.springbootplus.system.service.*;
import io.geekidea.springbootplus.system.utils.HttpDownLoad;
import io.geekidea.springbootplus.system.utils.Utils;
import io.geekidea.springbootplus.system.vo.LoginSysUserTokenVo;
import io.geekidea.springbootplus.system.vo.ScheduleSaveVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 控制器
 *
 * @author miko
 * @since 2020-10-15
 */
@Slf4j
@RestController
@RequestMapping("/schedule")
@Module("system")
@Api(value = "API", tags = {""})
public class ScheduleControllerExtra extends BaseController {

    @Autowired
    private ScheduleService scheduleService;

    @Autowired
    private TaskService taskService;

    @Autowired
    LoginService loginService;

    @Lazy
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    DormitoryService dormitoryService;

    @Autowired
    ParcelCenterService parcelCenterService;

    /**
     * 获取配送员某天的调度信息根据楼层group by
     * @return
     */
    @PostMapping("/getDormitoryToDo")
    @OperationLog(name = "所有列表", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<Map<String, List<Task>>> getDormitoryToDo(@CurrentCarrier CurrentCarrierInfo currentCarrierInfo, @RequestBody JSONObject jsonObject) throws Exception {
        String workType = jsonObject.getString("workType");

        String date = jsonObject.getString("date");

        String period = jsonObject.getString("period");

        Integer carrierID = currentCarrierInfo.getCarrier().getCarrierID();

        int schoolID = currentCarrierInfo.getSchool().getSchoolID();
        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getSchoolID, schoolID)
                .eq(Schedule::getWorkType, workType)
                .eq(Schedule::getCarrierID, carrierID)
                .like(Schedule::getSDate, date);

        if (!StringUtils.isEmpty(period)) {
            wrapper.eq(Schedule::getPeriod, period);
        }

        List<Schedule> list = scheduleService.getAllList(wrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        List<Task> allList = new ArrayList<>();
        //获取上午的只能显示12点前的，下午则包含上午没完成的
        for (Schedule schedule : list) {
            schedule.setSDateStr(simpleDateFormat.format(schedule.getSDate()));
            Date deadLine = new Date();

            if (schedule.getPeriod().equals("0")) {
                String s = simpleDateFormat.format(deadLine);
                s = s + " 12:00:00";
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                deadLine = sdf.parse(s);
            }


            LambdaQueryWrapper<Task> w = new LambdaQueryWrapper<Task>()
                    .eq(Task::getSchoolID,schoolID)
                    .eq(Task::getParcelCenterName, schedule.getParcelCenterName())
                    .lt(Task::getSubmitTime,deadLine)
                    .gt(Task::getSubmitTime,date).eq(Task::getTakePersonId,carrierID)
                    .eq(Task::getStatus, TaskStatusConstant.TAKED_UNSEND);

            List<Task> l = taskService.list(w);

            allList.addAll(l);
        }


        Map<String, List<Task>> map = allList.stream().collect(Collectors.groupingBy(Task::getDormitoryName));

        return ApiResult.ok(map);

    }


        /**
         * 获取配送员某天的调度信息
         * @return
         */
    @PostMapping("/getByDateAndCarrier")
    @OperationLog(name = "所有列表", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<List<Schedule>> getBySchool(@CurrentCarrier CurrentCarrierInfo currentCarrierInfo, @RequestBody JSONObject jsonObject) throws Exception {
        String workType = jsonObject.getString("workType");

        String date = jsonObject.getString("date");

        String period = jsonObject.getString("period");

        Integer carrierID = currentCarrierInfo.getCarrier().getCarrierID();

        int schoolID = currentCarrierInfo.getSchool().getSchoolID();
        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getSchoolID, schoolID)
                .eq(Schedule::getWorkType, workType)
                .eq(Schedule::getCarrierID, carrierID)
                .like(Schedule::getSDate, date);

        if (!StringUtils.isEmpty(period)) {
            wrapper.eq(Schedule::getPeriod, period);
        }

        List<Schedule> list = scheduleService.getAllList(wrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        //获取上午的只能显示12点前的，下午则包含上午没完成的
        for (Schedule schedule : list) {
            schedule.setSDateStr(simpleDateFormat.format(schedule.getSDate()));
            Date deadLine = new Date();

            if (schedule.getPeriod().equals("0")) {
                String s = simpleDateFormat.format(deadLine);
                s = s + " 12:00:00";
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                deadLine = sdf.parse(s);
            }
            int taskNum = taskService.getToDoAndDoneTask(schoolID, schedule.getParcelCenterName(), deadLine, workType,"").size();

            int taskTODONum = taskService.getToDoTask(schoolID, schedule.getParcelCenterName(), deadLine, workType).size();

            if (workType.equals("取件员")) {
            } else {
                taskNum = taskService.getToDoAndDoneTask(schoolID, schedule.getDormitoryName(), deadLine, workType,"").size();
                taskTODONum = taskService.getToDoTask(schoolID, schedule.getDormitoryName(), deadLine, workType).size();

            }
            schedule.setTaskNum(taskNum);

            schedule.setToDoTaskNum(taskTODONum);

        }
        return ApiResult.ok(list);
    }

    /**
     * 分页列表
     *
     * @return
     */
    @PostMapping("/share/checkToken2")
    @OperationLog(name = "生成二维码", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<?> checkToken2(@RequestBody JSONObject jsonObject) throws Exception {
        String parcelCenterId = jsonObject.getString("d");
        String schoolID = jsonObject.getString("s");
        String key = jsonObject.getString("t");

        ParcelCenter parcelCenter = parcelCenterService.getOne(new LambdaQueryWrapper<ParcelCenter>().eq(ParcelCenter::getCenterID, parcelCenterId));

        String token = "";

        try {
            token = (String) redisTemplate.opsForValue().get(key);
        }catch (Exception e){

        }

        Map<String,String> map = new HashMap<>();
        map.put("parcelCenterName",parcelCenter.getName());
        map.put("token",token);
        return ApiResult.ok(map);
    }
    /**
     * 分页列表
     *
     * @return
     */
    @PostMapping("/share/checkToken")
    @OperationLog(name = "生成二维码", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<?> checkToken(@RequestBody JSONObject jsonObject) throws Exception {
        String dormitoryID = jsonObject.getString("d");
        String schoolID = jsonObject.getString("s");
        String key = jsonObject.getString("t");

        Dormitory dormitory = dormitoryService.getOne(new LambdaQueryWrapper<Dormitory>().eq(Dormitory::getSchoolID,schoolID).eq(Dormitory::getDormitoryID,dormitoryID));

        String token = "";

        try {
            token = (String) redisTemplate.opsForValue().get(key);
        }catch (Exception e){

        }

        Map<String,String> map = new HashMap<>();
        map.put("dormitoryName",dormitory.getName());
        map.put("token",token);
        return ApiResult.ok(map);
    }


    /**
     * 分页列表
     *
     * @return
     */
    @PostMapping("/share/getToken")
    @OperationLog(name = "生成二维码", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<?> getToken(@RequestBody JSONObject jsonObject) throws Exception {
        String key = jsonObject.getString("key");

        String token = (String) redisTemplate.opsForValue().get(key);

        return ApiResult.ok(token);
    }

        /**
         * 分页列表
         *
         * @return
         */
    @GetMapping("/share/geneCode")
    @OperationLog(name = "生成二维码", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public void geneCode(@CurrentCarrier CurrentCarrierInfo currentCarrierInfo,@RequestParam String dormitoryName,@RequestParam String workType,
                         @RequestParam String period, HttpServletResponse response) throws Exception {

        final WxMaService wxService = WxMaConfiguration.getAdminService();

        String res = Utils.doGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxbc40f5a57f328fa8&secret=1a3a9edb7fceb59df38b06bc9e0eba15");

        int schoolID = currentCarrierInfo.getSchool().getSchoolID();

        LoginSysUserTokenVo loginSysUserTokenVo = loginService.wxLogin(currentCarrierInfo.getCarrier().getOpenID());

        String t = generatePassword(6);

        redisTemplate.opsForValue().set(t, loginSysUserTokenVo.getToken(), 6, TimeUnit.HOURS);

        JSONObject o = JSON.parseObject(res);
        String token = o.getString("access_token");

        JSONObject sendJSON = new JSONObject();

        if(workType.equals("派送员")){
            Dormitory dormitory = dormitoryService.getOne(new LambdaQueryWrapper<Dormitory>().eq(Dormitory::getSchoolID,schoolID).eq(Dormitory::getName,dormitoryName));

            sendJSON.put("scene", "d=" + dormitory.getDormitoryID() +",s="+schoolID+",p="+period+",t="+t);
            sendJSON.put("page", "pages/wbListPaijian");
            sendJSON.put("width", 220);
        }else{
            ParcelCenter parcelCenter = parcelCenterService.getOne(new LambdaQueryWrapper<ParcelCenter>().eq(ParcelCenter::getSchoolID,schoolID).eq(ParcelCenter::getName,dormitoryName));

            sendJSON.put("scene", "d=" + parcelCenter.getCenterID() +",s="+schoolID+",p="+period+",t="+t);
            sendJSON.put("page", "pages/wbListQujian");
            sendJSON.put("width", 220);
        }


        String body = JSON.toJSONString(sendJSON);

//        System.out.println("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token);
//        System.out.println(body);

        HttpDownLoad.download("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token, body, response);
    }


    /**
     * 随机生成密码
     *
     * @param length 密码的长度
     * @return 最终生成的密码
     */
    private static String generatePassword(int length) {
        // 最终生成的密码
        String password = "";
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            // 随机生成0或1，用来确定是当前使用数字还是字母 (0则输出数字，1则输出字母)
            int charOrNum = random.nextInt(2);
            if (charOrNum == 1) {
                // 随机生成0或1，用来判断是大写字母还是小写字母 (0则输出小写字母，1则输出大写字母)
                int temp = random.nextInt(2) == 1 ? 65 : 97;
                password += (char) (random.nextInt(26) + temp);
            } else {
                // 生成随机数字
                password += random.nextInt(10);
            }
        }
        return password;
    }


    /**
     * 分页列表
     *
     * @return
     */
    @PostMapping("/getBySchool")
    @OperationLog(name = "所有列表", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<Map<String, List<Schedule>>> getBySchool(@CurrentAdmin CurrentAdminInfo currentAdminInfo, @RequestBody JSONObject jsonObject) throws Exception {
        String workType = jsonObject.getString("workType");
        int schoolID = currentAdminInfo.getSchool().getSchoolID();
        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getSchoolID, schoolID).eq(Schedule::getWorkType, workType);
        List<Schedule> list = scheduleService.getAllList(wrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        for (Schedule schedule : list) {
            schedule.setSDateStr(simpleDateFormat.format(schedule.getSDate()));
        }

        Map<String, List<Schedule>> map = list.stream().collect(Collectors.groupingBy(Schedule::getSDateStr));
        return ApiResult.ok(map);
    }


    /**
     * 获取某个配送员的调度日历
     *
     * @return
     */
    @PostMapping("/getCarrierCalendar")
    @OperationLog(name = "所有列表", type = OperationLogType.PAGE)
    @ApiOperation(value = "所有列表", response = Schedule.class)
    public ApiResult<Map<String, List<Schedule>>> getCarrierCalendar(@CurrentCarrier CurrentCarrierInfo currentCarrierInfo, @RequestBody JSONObject jsonObject) throws Exception {
        int schoolID = currentCarrierInfo.getSchool().getSchoolID();

        int carrierID = currentCarrierInfo.getCarrier().getCarrierID();

        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getSchoolID, schoolID).eq(Schedule::getCarrierID, carrierID);
        List<Schedule> list = scheduleService.getAllList(wrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        for (Schedule schedule : list) {
            schedule.setSDateStr(simpleDateFormat.format(schedule.getSDate()));
        }

        Map<String, List<Schedule>> map = list.stream().collect(Collectors.groupingBy(Schedule::getSDateStr));
        return ApiResult.ok(map);
    }



    /**
     * 获取未来 第 past 天的日期
     * @param past
     * @return
     */
    public static Date getFetureDate(int past,Date date) {
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);

        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + past);
        Date today = calendar.getTime();
        return today;
    }


    @PostMapping("/clearDayAfter")
    @OperationLog(name = "保存", type = OperationLogType.PAGE)
    @ApiOperation(value = "保存", response = Schedule.class)
    public ApiResult<?> clearDayAfter(@RequestBody ScheduleSaveVo scheduleSaveVo, @CurrentAdmin CurrentAdminInfo currentAdminInfo) throws Exception {
        int schoolID = currentAdminInfo.getSchool().getSchoolID();

        String workType = scheduleSaveVo.getWorkType();

        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<Schedule>()
                .eq(Schedule::getSchoolID, schoolID)
                .eq(Schedule::getWorkType, workType)
                .gt(Schedule::getSDate,scheduleSaveVo.getDate());
        scheduleService.remove(wrapper);

        wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getSchoolID, schoolID).eq(Schedule::getWorkType, workType);
        List<Schedule> list = scheduleService.getAllList(wrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        for (Schedule schedule : list) {
            schedule.setSDateStr(simpleDateFormat.format(schedule.getSDate()));
        }

        Map<String, List<Schedule>> map = list.stream().collect(Collectors.groupingBy(Schedule::getSDateStr));
        return ApiResult.ok(map);
    }



        /**
         * 保存调度信息
         *
         * @return
         */
    @PostMapping("/saveSchedule")
    @OperationLog(name = "保存", type = OperationLogType.PAGE)
    @ApiOperation(value = "保存", response = Schedule.class)
    public ApiResult<Map<String, List<Schedule>>> getBySchool(@RequestBody ScheduleSaveVo scheduleSaveVo, @CurrentAdmin CurrentAdminInfo currentAdminInfo) throws Exception {
        int schoolID = currentAdminInfo.getSchool().getSchoolID();
        int adminID = currentAdminInfo.getAdmin().getAdminID();

        String period = scheduleSaveVo.getPeriod();

        String workType = scheduleSaveVo.getWorkType();

        Date date = scheduleSaveVo.getDate();
        List<Date> dates = new ArrayList<>();

        Calendar calendar=Calendar.getInstance();
        int today = calendar.get(Calendar.DAY_OF_WEEK)-1;
        if(scheduleSaveVo.isFillDay()){
            for (int i = 0;i <= scheduleSaveVo.getWeekSize();i++){
                for(int w: scheduleSaveVo.getWeekcheck()){
                    int ff = w-today+7*i;
                    if(ff>=0){
                        Date d = getFetureDate(ff, date);
                        dates.add(d);
                    }
                }
            }
        }


        int interval = 0;

        if(scheduleSaveVo.isFillWeek()){
            interval = 365;
        }

        if(scheduleSaveVo.isFillMonth()){
            interval = 30;
        }

        for (int i = 0;i<= interval;i++){
            Date d = getFetureDate(i,date);
            dates.add(d);
        }

        for(Date item : dates){

            try {
                List<Schedule> list = scheduleSaveVo.getSchedules();

                LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(Schedule::getSchoolID, schoolID)
                        .eq(Schedule::getPeriod, period)
                        .eq(Schedule::getSDate, item)
                        .eq(Schedule::getWorkType, workType);

                scheduleService.remove(wrapper);

                for (Schedule schedule : list) {
                    schedule.setSDate(item);
                    schedule.setWorkType(workType);
                    schedule.setPeriod(period);
                    schedule.setSchoolID(schoolID);
                    schedule.setAdminID(adminID);

                    scheduleService.saveSchedule(schedule);
                }
            }catch (Exception e){
                continue;
            }
        };


        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getSchoolID, schoolID).eq(Schedule::getWorkType, workType);
        List<Schedule> list = scheduleService.getAllList(wrapper);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        for (Schedule schedule : list) {
            schedule.setSDateStr(simpleDateFormat.format(schedule.getSDate()));
        }

        Map<String, List<Schedule>> map = list.stream().collect(Collectors.groupingBy(Schedule::getSDateStr));
        return ApiResult.ok(map);
    }

}